﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.SqlClient;
using System.Data;



namespace VisionarySystems.TimeRegi
{
    public class WorkTimeCalculator
    {
        private const int LOAD_DAYS_COUNT = 100; // How many days should be loaded as default

        #region Private Members
        private Dictionary<DateTime, TimeSpan> WorkedTime = new Dictionary<DateTime, TimeSpan>();
        private TimeSpan m_BreakPerDayKey;
        private DateTime m_CurrentStartTime;
        private DateTime DataStartDate = DateTime.MaxValue;
        private DateTime DataEndDate = DateTime.Now.Date;
        #endregion

        #region Ctor

        public WorkTimeCalculator(TimeSpan BreakPerDayKey, DateTime CurrentStartTime)
        {
            m_BreakPerDayKey = BreakPerDayKey;
            m_CurrentStartTime = CurrentStartTime;
            Clear();
        }

        #endregion

        #region Properties

        public TimeSpan BreakPerDay
        {
            get { return m_BreakPerDayKey; }
        }

        #endregion

        #region public methods

        public void LoadValues()
        {
            Clear(); 
            for (int DayNo = 0; DayNo <= LOAD_DAYS_COUNT; DayNo++)
            {
                DateTime GetDay = DateTime.Today.Date.AddDays(-1 * DayNo);
                AddDay(GetDay, new TimeSpan(0, 0, DatabaseLayer.GetSecondsInPeriod(GetDay, GetDay, (int)TimeSlotTypes.WorkTime)));
            }
        }

        /// <summary>
        /// Returns the work time in the period, with break time subtracted
        /// </summary>
        /// <param name="Startdate"></param>
        /// <param name="EndDate"></param>
        /// <param name="AddDaysOff"></param>
        /// <returns></returns>
        public TimeSpan GetTime(DateTime Startdate, DateTime EndDate, bool AddDaysOff = false)
        {
            if (!(
                      (CheckDayAllowed(Startdate)) &&
                      (CheckDayAllowed(EndDate))
                                                         ))
            {
                throw new ArgumentOutOfRangeException(string.Format("Datoerne skal være mellem {0} og {1}", DataStartDate, DateTime.Now.Date));
            }

            TimeSpan Result = new TimeSpan();
            TimeSpan DayValue;
            for (DateTime DateNo = Startdate; DateNo <= EndDate; DateNo = DateNo.AddDays(1))
            {
                WorkedTime.TryGetValue(DateNo.Date, out DayValue);
                //If Date is not registred ( And its not today)
                if ((DateNo.Date != DateTime.Now.Date) && (DayValue.Ticks == 0) && (AddDaysOff))
                    Result += HoursPerDay(DateNo.DayOfWeek); // Add the standard value, if AddDayOff is true (plus BreakTime)
                else
                {
                    Result += DayValue;                 // Get the stored time
                    Result += GetRunningTime(DateNo);   // Get the Current Time
                    // Subtract the break time
                    if (DayValue + GetRunningTime(DateNo) > GetBreakTime(DateNo))
                        Result -= GetBreakTime(DateNo);
                }
            }
            return Result;
        }

        public TimeSpan HoursPerDay(DayOfWeek TheDay)
        {
            switch (TheDay)
            {
                case DayOfWeek.Monday:
                case DayOfWeek.Tuesday:
                case DayOfWeek.Wednesday:
                case DayOfWeek.Thursday:
                    return new TimeSpan(7, 30, 0);
                case DayOfWeek.Friday:
                    return new TimeSpan(7, 00, 0);
                default: return new TimeSpan();
            }
        }

        public void AddDay(DateTime ThisDate, TimeSpan Value)
        {
            WorkedTime.Add(ThisDate, Value);
            if ( ThisDate > DataEndDate )
                DataEndDate = ThisDate ;
            if (ThisDate < DataStartDate)
                DataStartDate = ThisDate;
        }

        public void Clear()
        {
            WorkedTime.Clear();
            DataStartDate = DateTime.MaxValue;
            DataEndDate = DateTime.Now.Date;
        }

        /// <summary>
        /// Returns the Breaktime for a specified date, not calculating, if work was done on that day or not
        /// </summary>
        /// <param name="ThisDate"></param>
        /// <returns></returns>
        public TimeSpan GetBreakTime(DateTime ThisDate)
        {
            TimeSpan Result;
            TimeSpan BreakTime = m_BreakPerDayKey;
            if ((ThisDate.DayOfWeek == DayOfWeek.Saturday) || (ThisDate.DayOfWeek == DayOfWeek.Sunday)) // Satterday and sunday includes no breaks 
                Result = new TimeSpan();
            else if (ThisDate.Date != DateTime.Now.Date)  // If its not today, use the full break time
                Result = BreakTime;
            else if ((DateTime.Now.Hour == 12) &&
                     (DateTime.Now < DateTime.Now.Date.AddHours(12).Add(m_BreakPerDayKey)))// Is the time between todays break start / stop
                Result = new TimeSpan(0, DateTime.Now.Minute, DateTime.Now.Second);
            else
                Result = BreakTime;
            return Result;
        }

        #endregion 

        #region Private methods

        /// <summary>
        /// Returns if the date is in the range of start and stop dates
        /// </summary>
        /// <param name="CheckDate"></param>
        /// <returns></returns>
        private bool CheckDayAllowed(DateTime CheckDate)
        {
            return ((CheckDate >= DataStartDate) && (CheckDate <= DataEndDate)); 
        }
        
        /// <summary>
        /// Returns when how long time the current TimeSLot has been running
        /// If No Timeslot is active, it returns 0
        /// </summary>
        /// <param name="DateNo"></param>
        /// <returns></returns>
        private TimeSpan GetRunningTime(DateTime DateNo)
        {
            DateTime PeriodStart = DateTime.MinValue;
            DateTime PeriodStop = DateTime.MinValue;
            
            // If it has started today
            if (DateNo.Date == m_CurrentStartTime.Date)
                PeriodStart = m_CurrentStartTime;
            else if (DateNo.Date > m_CurrentStartTime.Date) // If it has started before today
                PeriodStart = DateNo.Date;
            else
                return new TimeSpan(); // StartTime is in the futur (Not running now)

            if (DateNo.Date == DateTime.Now.Date)
                PeriodStop = DateTime.Now;
            else if (DateNo.Date < DateTime.Now.Date )
                PeriodStop = DateNo.Date.AddDays(1);
            if (( PeriodStart == DateTime.MinValue) || ( PeriodStop == DateTime.MinValue))
                return new TimeSpan ();
            else
                return PeriodStop.Subtract(PeriodStart);
        }

        #endregion

        /*TimeSpan WorkedTimeToday = DateTime.Now.Subtract(CurrentStartTime);

TimeSpan DayValue ;
WorkedTime.TryGetValue(DateTime.Today.Date, out DayValue);
WorkedTimeToday += DayValue;
                    
*/
    }
}
